#include "udp_common.hpp"
#include <thread>
#include <sstream>
#include <unordered_map>
class UdpServer
{
public:
    UdpServer(int port) : port_(port) {}
  void run() {
        sock_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sock_ < 0) { perror("socket"); exit(1); }

        sockaddr_in addr{};
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_ANY;
        addr.sin_port = htons(port_);

        if (bind(sock_, (sockaddr*)&addr, sizeof(addr)) < 0) {
            perror("bind"); exit(1);
        }

        std::cout << "[UDP Server] listening on port " << port_ << " ...\n";

        std::thread recv_thr(&UdpServer::recvLoop, this);
        std::thread send_thr(&UdpServer::sendLoop, this);
        recv_thr.join();
        send_thr.join();
    }
private:

    //接收线程：收包 + 回 ACK + 检测丢包
void recvLoop() 
{
    char buf[BUF_SIZE];
     //  1 声明一个空的 sockaddr_in client
    sockaddr_in client;
    socklen_t len = sizeof(client);
    while (true) {
       
        //  2 把它的地址传给 recvfrom，内核在返回时把 客户端的 IP+端口 填进去
        ssize_t n = recvfrom(sock_, buf, sizeof(buf) - 1, 0, (sockaddr*)&client, &len);
        if (n <= 0) continue;
        buf[n] = '\0';

        // 解析客户端序号
        int seq; 
        char content[BUF_SIZE];
        sscanf(buf, "%d:%[^\n]", &seq, content);

std::cout << "[Server] received seq=" << seq << " body=" << content << '\n';

        // 回 ACK（携带服务器当前发送窗口，便于客户端降速）
        std::ostringstream oss;
        oss << "ACK:" << seq << ":" << cwnd_;
        std::string ack = oss.str();
        sendto(sock_, ack.c_str(), ack.size(), 0, (sockaddr*)&client, len);

           

        // 如果检测到乱序/丢包，服务器也可主动降速
        if (seq != lastRecvSeq_ + 1) {
            ssthresh_ = std::max(cwnd_ / 2, 1);
            cwnd_     = 1;
        }
        lastRecvSeq_ = seq;
    }
}

    // 发送线程：窗口内持续发送 + 超时重传
    void sendLoop()
    {
        char buf[BUF_SIZE];
        sockaddr_in client; // 记录最后一次客户端地址
        socklen_t len = sizeof(client);
        while (true)
        {
            // 举例：每 100 ms 检查一下超时并重传
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
            auto now = std::chrono::steady_clock::now();
            for (auto &[seq, t] : sentTime_)
            {
                if (std::chrono::duration_cast<std::chrono::milliseconds>(now - t).count() > 1000)
                {
                    ssthresh_ = std::max(cwnd_ / 2, 1);
                    cwnd_ = 1;
                    std::string pkt = std::to_string(seq) + ":" + sendBuf_[seq];
                    sendto(sock_, pkt.c_str(), pkt.size(), 0, (sockaddr *)&client, len);
                    sentTime_[seq] = now;
                    break;
                }
            }
        }
    }

    int port_;
    int sock_;
    int cwnd_ = INIT_CWND; // 服务器发送窗口
    int ssthresh_ = MAX_WINDOW / 2;
    int nextSeq_ = 0;                              // 下一个要发的序号
    std::unordered_map<int, std::string> sendBuf_; // 缓存待确认数据
    std::unordered_map<int, std::chrono::steady_clock::time_point> sentTime_;
    int lastRecvSeq_ = 0;   // 记录每个客户端最新收到的序号
};

int main()
{
    // 服务器必须“公布”自己的端口号（有时还要公布 IP），否则客户端根本不知道把数据包扔到哪；
    // 至于服务器本身，端口号是 自己 bind 时指定的，IP 在监听 INADDR_ANY 时由内核自动关联到本机所有网卡
    UdpServer srv(PORT);
    srv.run();
    return 0;
}
